package com.lottery.im.base;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.ActivityOptions;
import android.os.Build;
import android.os.Looper;
import android.support.v4.app.FragmentManager;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;

/**
 * Created by Chaojun Wang on 6/9/14.
 */
public class Utils {
  private Utils() {
  }

  /**
   * Convert a translucent themed Activity
   * {@link android.R.attr#windowIsTranslucent} to a fullscreen opaque
   * Activity.
   * <p>
   * Call this whenever the background of a translucent Activity has changed
   * to become opaque. Doing so will allow the {@link android.view.Surface} of
   * the Activity behind to be released.
   * <p>
   * This call has no effect on non-translucent activities or on activities
   * with the {@link android.R.attr#windowIsFloating} attribute.
   */
  public static void convertActivityFromTranslucent(Activity activity) {
    try {
      @SuppressLint("PrivateApi") Method method =
          Activity.class.getDeclaredMethod("convertFromTranslucent");
      method.setAccessible(true);
      method.invoke(activity);
    } catch (Throwable ignore) {
    }
  }

  /**
   * Convert a translucent themed Activity
   * {@link android.R.attr#windowIsTranslucent} back from opaque to
   * translucent following a call to
   * {@link #convertActivityFromTranslucent(Activity)} .
   * <p>
   * Calling this allows the Activity behind this one to be seen again. Once
   * all such Activities have been redrawn
   * <p>
   * This call has no effect on non-translucent activities or on activities
   * with the {@link android.R.attr#windowIsFloating} attribute.
   */
  public static void convertActivityToTranslucent(Activity activity) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
      convertActivityToTranslucentAfterL(activity);
    } else {
      convertActivityToTranslucentBeforeL(activity);
    }
  }

  /**
   * Calling the convertToTranslucent method on platforms before Android 5.0
   */
  private static void convertActivityToTranslucentBeforeL(Activity activity) {
    try {
      Class<?>[] classes = Activity.class.getDeclaredClasses();
      Class<?> translucentConversionListenerClazz = null;
      for (Class clazz : classes) {
        if (clazz.getSimpleName().contains("TranslucentConversionListener")) {
          translucentConversionListenerClazz = clazz;
        }
      }
      @SuppressLint("PrivateApi") Method method =
          Activity.class.getDeclaredMethod("convertToTranslucent",
              translucentConversionListenerClazz);
      method.setAccessible(true);
      method.invoke(activity, new Object[] {
          null
      });
    } catch (Throwable ignore) {
    }
  }

  /**
   * Calling the convertToTranslucent method on platforms after Android 5.0
   */
  @TargetApi(Build.VERSION_CODES.LOLLIPOP)
  private static void convertActivityToTranslucentAfterL(Activity activity) {
    try {
      @SuppressLint("PrivateApi") Method getActivityOptions =
          Activity.class.getDeclaredMethod("getActivityOptions");
      getActivityOptions.setAccessible(true);
      Object options = getActivityOptions.invoke(activity);

      Class<?>[] classes = Activity.class.getDeclaredClasses();
      Class<?> translucentConversionListenerClazz = null;
      for (Class clazz : classes) {
        if (clazz.getSimpleName().contains("TranslucentConversionListener")) {
          translucentConversionListenerClazz = clazz;
        }
      }
      @SuppressLint("PrivateApi") Method convertToTranslucent =
          Activity.class.getDeclaredMethod("convertToTranslucent",
              translucentConversionListenerClazz, ActivityOptions.class);
      convertToTranslucent.setAccessible(true);
      convertToTranslucent.invoke(activity, null, options);
    } catch (Throwable ignore) {
    }
  }

  public static void assertInMainThread() {
    if (Looper.myLooper() != Looper.getMainLooper()) {
      StackTraceElement[] elements = Thread.currentThread().getStackTrace();
      String methodMsg = null;
      if (elements != null && elements.length >= 4) {
        methodMsg = elements[3].toString();
      }
      throw new IllegalStateException("Call the method must be in main thread: " + methodMsg);
    }
  }

  static void findAndModifyOpInBackStackRecord(FragmentManager fragmentManager, int backStackIndex,
      OpHandler handler) {
    if (fragmentManager == null || handler == null) {
      return;
    }
    int backStackCount = fragmentManager.getBackStackEntryCount();
    if (backStackCount > 0) {
      if (backStackIndex >= backStackCount || backStackIndex < -backStackCount) {
        return;
      }
      if (backStackIndex < 0) {
        backStackIndex = backStackCount + backStackIndex;
      }
      try {
        FragmentManager.BackStackEntry backStackEntry =
            fragmentManager.getBackStackEntryAt(backStackIndex);

        Field opsField = backStackEntry.getClass().getDeclaredField("mOps");
        opsField.setAccessible(true);
        Object opsObj = opsField.get(backStackEntry);
        if (opsObj instanceof List<?>) {
          List<?> ops = (List<?>) opsObj;
          for (Object op : ops) {
            if (handler.handle(op)) {
              return;
            }
          }
        }
      } catch (NoSuchFieldException e) {
        e.printStackTrace();
      } catch (IllegalAccessException e) {
        e.printStackTrace();
      }
    }
  }

  interface OpHandler {
    boolean handle(Object op);
  }
}
